package com.ttg.common.utils;

import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author huyangzou
 * @create 2020-12-01 10:28
 */
public class ObjectUtils {

    /**
     * Map转对象
     */
    public static <T> T mapToObject(Map<String, String> map, Class<T> beanClass) throws Exception {
        if (map == null) {
            return null;
        }
        T obj = beanClass.newInstance();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            ReflectionUtils.makeAccessible(field);
            field.set(obj, map.get(field.getName()));
        }
        return obj;
    }

    /**
     * 对象转Map
     */
    public static Map<String, String> objectToMap(Object obj) throws Exception {
        if (obj == null) {
            return null;
        }
        Map<String, String> reMap = new HashMap<>(12);
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            Field f = obj.getClass().getDeclaredField(field.getName());
            ReflectionUtils.makeAccessible(f);
            Object o = f.get(obj);
            if (o != null) {
                if (o instanceof String) {
                    reMap.put(field.getName(), (String) o);
                } else if (o instanceof BigDecimal) {
                    reMap.put(field.getName(), o.toString());
                } else if (o instanceof Integer) {
                    reMap.put(field.getName(), (String.valueOf(o)));
                } else if (o instanceof Long) {
                    reMap.put(field.getName(), (String.valueOf(o)));
                } else if (o instanceof LocalDateTime) {
                    reMap.put(field.getName(), ((LocalDateTime) o).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
                }
            }
        }
        return reMap;
    }

    /**
     * 转map
     */
    public static <T> T mapToObj(Map<String, Object> map, Class<T> clazz) throws Exception {
        T obj = clazz.newInstance();
        if(map != null && map.size() > 0) {
            for(Map.Entry<String, Object> entry : map.entrySet()) {
                //属性名
                String propertyName = entry.getKey();
                Object value = entry.getValue();
                String setMethodName = "set"
                        + propertyName.substring(0, 1).toUpperCase()
                        + propertyName.substring(1);
                Field field = getClassField(clazz, propertyName);
                if(field==null){
                    continue;
                }
                Class<?> fieldTypeClass = field.getType();
                value = convertValType(value, fieldTypeClass);
                try{
                    clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
                }catch(NoSuchMethodException e){
                    e.printStackTrace();
                }
            }
        }
        return obj;
    }

    /**
     * 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
     */
    private static Field getClassField(Class<?> clazz, String fieldName) {
        if( Object.class.getName().equals(clazz.getName())) {
            return null;
        }
        Field []declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        Class<?> superClass = clazz.getSuperclass();
        if(superClass != null) {
            // 简单的递归一下
            return getClassField(superClass, fieldName);
        }
        return null;
    }

    /**
     * 将Object类型的值，转换成bean对象属性里对应的类型值
     */
    private static Object convertValType(Object value, Class<?> fieldTypeClass) {
        Object retVal;
        if(Long.class.getName().equals(fieldTypeClass.getName())
                || long.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Long.parseLong(value.toString());
        } else if(Integer.class.getName().equals(fieldTypeClass.getName())
                || int.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Integer.parseInt(value.toString());
        } else if(Float.class.getName().equals(fieldTypeClass.getName())
                || float.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Float.parseFloat(value.toString());
        } else if(Double.class.getName().equals(fieldTypeClass.getName())
                || double.class.getName().equals(fieldTypeClass.getName())) {
            retVal = Double.parseDouble(value.toString());
        } else {
            retVal = value;
        }
        return retVal;
    }


    /**
     * 通过目标属性 和 目标属性对应的值  确认是否是目标对象
     * @param obj 源对象
     * @param targetKey 源对象属性
     * @param searchValue 源对象属性的值
     * @return boolean
     */
    public static boolean getTargetObj(Object obj, String targetKey, Object searchValue){
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.getName().equals(targetKey) && field.get(obj).equals(searchValue)) {
                    return true;
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}
